#include "drv_fsmc.h"
#include "stm32f7xx_hal.h"
#include <rtdevice.h>

#define fifo_full           66

#define write_date(offset,data) *((volatile unsigned short int *)(0x60000000 + (offset << 1))) = data
#define read_date(offset)   *((volatile unsigned short int *)(0x60000000 + (offset << 1)))

static int fsmc_initialize(void);

static int fsmc_initialize(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    FMC_NORSRAM_TimingTypeDef Timing;
    SRAM_HandleTypeDef hsram1;

    /** Perform the SRAM1 memory initialization sequence
     */
    hsram1.Instance = FMC_NORSRAM_DEVICE;
    hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();

    /* Peripheral clock enable */
    __HAL_RCC_FMC_CLK_ENABLE();

    /** FMC GPIO Configuration
    PD6   ------> FMC_NWAIT
    PD3   ------> FMC_CLK
    PB7   ------> NADV
    PD5   ------> FMC_NWE
    PD4   ------> FMC_NOE
    PD7   ------> CS0

    PD14  ------> FMC_D0
    PD15  ------> FMC_D1
    PD0   ------> FMC_D2
    PD1   ------> FMC_D3
    PE7   ------> FMC_D4
    PE8   ------> FMC_D5
    PE9   ------> FMC_D6
    PE10  ------> FMC_D7
    PE11  ------> FMC_D8
    PE12  ------> FMC_D9
    PE13  ------> FMC_D10
    PE14  ------> FMC_D11
    PE15  ------> FMC_D12
    PD8   ------> FMC_D13
    PD9   ------> FMC_D14
    PD10  ------> FMC_D15

    PD11  ------> FMC_A16
    PD12  ------> FMC_A17
    PD13  ------> FMC_A18
    PE3   ------> FMC_A19
    PE4   ------> FMC_A20
    PE5   ------> FMC_A21
    PE6   ------> FMC_A22
    PE2   ------> FMC_A23
    */

//    //full
//    GPIO_InitStruct.Pin = GPIO_PIN_2;
//  //GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//////////上降沿中断
//    GPIO_InitStruct.Pull = GPIO_PULLUP;
//    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);


    //NADV
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
                                                    |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
                                                    |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5
                          |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9
                          |GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
                          |GPIO_PIN_14|GPIO_PIN_15;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    /* Timing */                               //单位AHB时钟周期HCLK
    Timing.AddressSetupTime = 7;               //////////地址建立时间       0-15
    Timing.AddressHoldTime = 2;                //////////地址保持时间       1-15
    Timing.DataSetupTime = 20;                 /////18/////数据建立时间       1-256
    Timing.BusTurnAroundDuration = 0;          //////////总线周转时间       0-15
    Timing.CLKDivision = 0;                    //同步模式用
    Timing.DataLatency = 0;                    //同步模式用
    Timing.AccessMode = FMC_ACCESS_MODE_A;
    /* ExtTiming */

    /* hsram1.Init */
    hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
    hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_ENABLE;
    hsram1.Init.MemoryType = FMC_MEMORY_TYPE_NOR;
    hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
    hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
    hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
    hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
    hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
    hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_ENABLE;                ///////同步nwait 信号
    hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
    hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_ENABLE;     ///////异步nwait 信号
    hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
    hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;//
    hsram1.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;//
    hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;//

    if(HAL_SRAM_Init(&hsram1,&Timing,NULL) != HAL_OK){
        while(1);
    }

    return 0;
}
INIT_BOARD_EXPORT(fsmc_initialize);

void writeReg(unsigned int addr,unsigned int bit,unsigned int flag)
{
    unsigned int state = 0;
    state = read_date(addr);
    if(flag == 0)
    {
        write_date(addr, state & (~(0x0001 << bit)));
    }
    else
    {
        write_date(addr, state | 0x0001 << bit);
    }
}

unsigned int test;

long write_fpga(unsigned int add,unsigned int num)
{
    write_date(add,num);
    return 0;
}
FINSH_FUNCTION_EXPORT(write_fpga, write_fpga);

long read_fpga(unsigned int add)
{
    unsigned short int data;
    data = read_date(add);
    rt_kprintf("%d\r\n",data);

    return data;
}
FINSH_FUNCTION_EXPORT(read_fpga, read_fpga);

static unsigned int fsmclock = 0;

void full_iqr(void *args)
{
    fsmclock = 1;
}

long fsmctest()
{
    rt_pin_mode(fifo_full, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(fifo_full, PIN_IRQ_MODE_RISING, full_iqr, RT_NULL);
    rt_pin_irq_enable(fifo_full, PIN_IRQ_ENABLE);

    unsigned k = 1;

    while(k)
    {
        rt_kprintf("k:%d\r\n",k);
        k++;
    for(int j=0;j<4;j++)
    for(unsigned long i=0;i < 0x10000;i++)
    {
        while(fsmclock)
        {
            rt_thread_mdelay(1);
            if(rt_pin_read(fifo_full) == 0) fsmclock = 0;
        }
        write_date(500,i);
    }

    //read_lock,读sram锁上后该块不能写入
    //writeReg(501,0,1);//501.0 = 1

    rt_thread_mdelay(5);
    for(int j=0;j<4;j++)
    for(unsigned int i=0;i < 0x10000;i++)
    {
        unsigned int data = read_date(500);
        if(data!=i) {rt_kprintf("data error: i:%d,j:%d ,data:%d\r\n",i,j,data); k = 0;break;}
    }

    //解除read_lock
    //writeReg(501,0,0);//501.0 = 0

    }
    rt_kprintf("test done\r\n");

    return 0;
}
MSH_CMD_EXPORT(fsmctest,fsmctest);
FINSH_FUNCTION_EXPORT(fsmctest, fsmctest);

